Ext.ns('Ext.ux.tree');

/**
 * Creates new RemoteTreePanel
 * @constructor
 * @param {Object} config A config object
 */
Ext.ux.tree.RemoteTreePanel = Ext.extend(Ext.tree.TreePanel, {
 
	appendText        : '追加文件',
	
	collapseAllText   : '全部折叠',
	
	collapseText      : '折叠',
	
	deleteText        : '删除',	
	
	expandAllText     : '全部展开',
	
	expandText        : '展开',
	
	insertText        : '新建文件',
	
	newText           : '新文件',
		
	reloadText        : '重新加载',
	
	renameText        : '重命名',
	
	insertFolderText  : '新建文件夹',
	
	contextMenu       : true,

	reallyWantText    : '你真的想要',
	
	errorText         : '错误',
	
	allowLeafAppend   : true,

	appendIconCls     : 'icon-arrow-down',
	
	collapseAllIconCls: 'icon-collapse',

	collapseIconCls   : 'icon-collapse',

	deleteIconCls     : 'icon-cross',
	
	folderIconCls     : 'icon-folder-add',
	
	expandAllIconCls  : 'icon-expand',

	expandIconCls     : 'icon-expand',

	insertIconCls     : 'icon-arrow-right',	

	reloadIconCls     : 'icon-refresh',

	renameIconCls     : 'icon-pencil',
	
    border            : false,
    
	enableDD          : true,
    
    editable          : true,
    
    editTree          : false,
    
    enableC2P         : false,
    
    layout            : 'fit',

	cmdNames:{
		moveNode      : 'moveTreeNode',
		renameNode    : 'renameTreeNode',
		removeNode    : 'removeTreeNode',
		appendChild   : 'appendTreeChild',
		insertChild   : 'insertTreeChild',
		insertFolder  : 'insertTreeFolder'
	},


	/**
	 * @cfg {Object} editorConfig Configuration for Ext.tree.TreeEditor
	 */
	editorConfig     : {
		 cancelOnEsc     : true,
		 completeOnEnter : true,
		 ignoreNoChange  : false,
		 editDelay       : 0
	},

	/**
	 * @cfg {Object} editorFieldConfig Configuration for tree editor field
	 */
	editorFieldConfig: {
		 allowBlank     : false,
		 selectOnFocus  : true
	},

	paramNames       : {
		cmd             : 'cmd',
		id              : 'id',
		target          : 'target',
		point           : 'point',
		text            : 'text',
		newText         : 'newText',
		oldText         : 'oldText'
	}

	
    ,initComponent:function() {

        // hard coded config (cannot be changed from outside)
        var config = {};

		// todo: add other keys and put them to context menu
		if(!this.keys) {
			config.keys = (function() {
				var keys = [];
				if(true === this.editable) {
					keys.push({
						key:Ext.EventObject.DELETE,
						scope:this,
						stopEvent:true,
						handler:this.onKeyDelete
					});

					keys.push({
						key:Ext.EventObject.F2,
						scope:this,
						stopEvent:true,
						handler:this.onKeyEdit
					});
				}
				return keys;
			}.call(this));
		}
 
        Ext.apply(this, Ext.apply(this.initialConfig, config));
        Ext.ux.tree.RemoteTreePanel.superclass.initComponent.apply(this, arguments);
        
        
        /**
         * 创建所有的子节点.
         */  
		if(true === this.loader.preloadChildren) {
			this.loader.on({
				load:function(loader, node) {
					node.cascade(
						function(n) {
							loader.doPreload(n);
						}
					);
				}
			});
		}
		
		/**
		 * 创建 tree editor
		 */
		if(true === this.editable && !this.editor) {
			this.editor = new Ext.tree.TreeEditor(this, this.editorFieldConfig, this.editorConfig);
			this.editor.on({
				 complete : {
				 	scope    : this, 
				 	fn       : this.onEditComplete
				 },
				 beforestartedit : {
				 	scope    : this, 
				 	fn       : function(editor,boundEl,value) {
				 					if (this.editTree) {
					 			   		return this.editable; 
				 					} else {
					 			   		this.fireEvent('click',this.selectedNode);
					 			   		return (!this.editable); 
					 			   		
				 					}
				 			   }
				 }
			});
		}

		// remember selected node
		if(true === this.editable) {
			this.getSelectionModel().on({
				selectionchange:{
					scope   : this, 
					fn      : function(selModel, node) {
									this.selectedNode = node;
							  }
				}
			});
		}

		
		
		/**
		 * 创建右键菜单处理事件
		 */
		if(true === this.editable && !this.actions) {
			this.actions = {
				 reloadTree:new Ext.Action({
					 text:this.reloadText
					,iconCls:this.reloadIconCls
					,scope:this
					,handler:function() {
						this.root.reload();
					}
				})
				,expandNode:new Ext.Action({
					 text:this.expandText
					,iconCls:this.expandIconCls
					,scope:this
					,handler:this.onExpandNode
				})
				,expandAll:new Ext.Action({
					 text:this.expandAllText
					,iconCls:this.expandAllIconCls
					,scope:this
					,handler:this.onExpandAll
				})
				,collapseNode:new Ext.Action({
					 text:this.collapseText
					,iconCls:this.collapseIconCls
					,scope:this
					,handler:this.onCollapseNode
				})
				,collapseAll:new Ext.Action({
					 text:this.collapseAllText
					,iconCls:this.collapseAllIconCls
					,scope:this
					,handler:this.onCollapseAll
				})
				,renameNode:new Ext.Action({
					 text:this.renameText
					,iconCls:this.renameIconCls
					,scope:this
					,handler:this.onRenameNode
				})
				,removeNode:new Ext.Action({
					 text:this.deleteText
					,iconCls:this.deleteIconCls
					,scope:this
					,handler:this.onRemoveNode
				})
				,appendChild:new Ext.Action({
					 text:this.appendText
					,iconCls:this.appendIconCls
					,scope:this
					,handler:this.onAppendChild
				})
				,insertChild:new Ext.Action({
					 text:this.insertText
					,iconCls:this.insertIconCls
					,scope:this
					,handler:this.onInsertChild
				})
				,insertFolder:new Ext.Action({
					 text:this.insertFolderText
					,iconCls:this.folderIconCls
					,scope:this
					,handler:this.onInsertFolder
				})

			};
		}

		/**
		 * 创建菜单
		 */
		if(true === this.editable && true === this.contextMenu) {
			this.contextMenu = new Ext.menu.Menu([
				 new Ext.menu.TextItem({text:'', style:'font-weight:bold;margin:0px 4px 0px 27px;line-height:14px'})
				,'-'
				,this.actions.reloadTree
				,this.actions.expandAll
				,this.actions.collapseAll
				,'-'
				,this.actions.expandNode
				,this.actions.collapseNode
				,'-'
//				,this.actions.renameNode
//				,'-'
//				,this.actions.appendChild
				,this.actions.insertChild
				,this.actions.insertFolder
				,'-'
				,this.actions.removeNode
			]);
		}

		/**
		 * 菜单处理事件
		 */
		if(this.contextMenu) {
			this.on({contextmenu:{scope:this, fn:this.onContextMenu, stopEvent:true}});
			this.contextMenu.on({
				hide:{scope:this, fn:function() {
					this.editTree = false;
					this.actionNode = null;
				}}
				,show:{scope:this, fn:function() {
					this.editTree = true;
					var node = this.actionNode;
					var text = Ext.util.Format.ellipsis(node ? node.text : '', 12);
					this.contextMenu.items.item(0).el.update(text);
					//this.contextMenu.el.shadow.hide();
					this.contextMenu.el.shadow.show(this.contextMenu.el);
				}}
			});
		}

		
		// setup D&D
		if(true === this.enableDD) {
			this.on({
				 beforenodedrop:{scope:this, fn:this.onBeforeNodeDrop}
				,nodedrop:{scope:this, fn:this.onNodeDrop}
				,nodedragover:{scope:this, fn:this.onNodeDragOver}
				,startdrag:{scope:this, fn:this.onStartDrag}
			});

		}

		/**
		 * 添加处理事件
		 */
		this.addEvents(
			/**
			 * @event beforeremoverequest
			 * Fires before request is sent to the server, return false to cancel the event.
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Object} options Options as passed to Ajax.request
			 */
			 'beforeremoverequest'

			/**
			 * @event beforerenamerequest
			 * Fires before request is sent to the server, return false to cancel the event.
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Object} options Options as passed to Ajax.request
			 */
			,'beforerenamerequest'

			/**
			 * @event beforeappendrequest
			 * Fires before request is sent to the server, return false to cancel the event.
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Object} options Options as passed to Ajax.request
			 */
			,'beforeappendrequest'

			/**
			 * @event beforeinsertrequest
			 * Fires before request is sent to the server, return false to cancel the event.
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Object} options Options as passed to Ajax.request
			 */
			,'beforeinsertrequest'
			
			
			,'beforeinsertfolderrequest'

			/**
			 * @event beforeremoverequest
			 * Fires before request is sent to the server, return false to cancel the event.
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Object} options Options as passed to Ajax.request
			 */
			,'beforemoverequest'

			/**
			 * @event appendchildsuccess
			 * Fires after server returned success
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Ext.tree.AsyncTreeNode} node The node involved in action
			 */
			,'appendchildsuccess'

			/**
			 * @event insertchildsuccess
			 * Fires after server returned success
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Ext.tree.AsyncTreeNode} node The node involved in action
			 */
			,'insertchildsuccess'

			/**
			 * @event removenodesuccess
			 * Fires after server returned success
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Ext.tree.AsyncTreeNode} node The node involved in action
			 */
			,'removenodesuccess'

			/**
			 * @event renamenodesuccess
			 * Fires after server returned success
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Ext.tree.AsyncTreeNode} node The node involved in action
			 */
			,'renamenodesuccess'

			/**
			 * @event movenodesuccess
			 * Fires after server returned success
			 * @param {Ext.ux.tree.RemoteTreePanel} tree This tree panel
			 * @param {Ext.tree.AsyncTreeNode} node The node involved in action
			 */
			,'movenodesuccess'
		);

    } 

    

	/**
	 * initEvents override
	 *
	 * @private
	 */
	,initEvents:function() {
		Ext.ux.tree.RemoteTreePanel.superclass.initEvents.apply(this, arguments);
		if(true === this.enableDD) {
			// prevent dragging if the tree is not editable
			this.dragZone.onBeforeDrag = function(data, e) {
				var n = data.node;
				return n && n.draggable && !n.disabled && this.tree.editable;
			}; 
		}
	} 

	
	
	/**
	 * 服务器请求事件回调函数
	 * Server request (action) callback function)
	 * @param {Object} options Options used for request
	 * @param {Boolean} success
	 * @param {Object} response
	 */
	,actionCallback:function(options, success, response) {

		// remove loading indicator
		if(options.node) {
			options.node.getUI().afterLoad();
		}

		// failure handling
		if(true !== success) {
			this.showError(response.responseText);
			return;
		}
		var o;
		try {
			o = Ext.decode(response.responseText);
		}
		catch(ex) {
			this.showError(response.responseText);
			return;
		}
		if(true !== o.success) {
			this.showError(o.msg || o.msg);
			switch(options.action) {
				case 'appendChild':
				case 'insertChild':
				case 'insertFolder':
					options.node.parentNode.removeChild(options.node);
				break;

				default:
				break;
			}
			return;
		}
		if(!options.action) {
			this.showError('Developer error: no options.action');
		}

		
		// success handling - synchronize ui with server action
		switch(options.action) {
			case 'renameNode':
				options.node.setText(options.params.newText);
			break;

			case 'removeNode':
				options.node.parentNode.removeChild(options.node);
			break;

			case 'moveNode':
				if('append' === options.e.point) {
					options.e.target.expand();
				}
				this.dropZone.completeDrop(options.e);
			break;

			case 'appendChild':
			case 'insertChild':
				// change id of the appended/inserted node
				this.unregisterNode(options.node);
				options.node.id = o.node.id;
				options.node.attributes.url = o.node.url;
				Ext.fly(options.node.getUI().elNode).set({'ext:tree-node-id':o.node.id});
				this.registerNode(options.node);
				options.node.select();
				break;
			case 'insertFolder':
				this.unregisterNode(options.node);
				options.node.id = o.node.id;
				options.node.attributes.url = o.node.url;
				Ext.fly(options.node.getUI().elNode).set({'ext:tree-node-id':o.node.id});
				this.registerNode(options.node);
				options.node.select();
				options.node.expand(true,true,function(n){
					
				}.createDelegate(this));
				
				break;
		}
	
		this.fireEvent(options.action.toLowerCase() + 'success', this, options.node);

	} 

	
	/**
	 * Returne combined object of baseParams and params
	 * @private
	 * @param {Object} params params to combine with baseParams
	 */
	,applyBaseParams:function(params) {
		var o = Ext.apply({}, this.baseParams || this.loader.baseParams || {});
		Ext.apply(o, params || {});
		return o;
	}

	
	/**
	 * 新增节点
	 * Requests server to append the child node. Child node has already been appended
	 * at client but it is removed if server append fails
	 * 
	 * @param {Ext.tree.TreeNode} childNode node to append
	 * @param {Boolean} insert Do not apppend but insert flag
	 */
	,appendChild:function(childNode, insert) {

		var params = this.applyBaseParams();
		params[this.paramNames.cmd] = true === insert ? this.cmdNames.insertChild : this.cmdNames.appendChild;
		params[this.paramNames.id] = childNode.parentNode.id;
		params[this.paramNames.text] = childNode.text;

		var o = Ext.apply(this.getOptions(), {
			 action:true === insert ? 'insertChild' : 'appendChild'
			,node:childNode
			,params:params
		});

		if(false !== this.fireEvent('before' + (insert ? 'insert' : 'append') + 'request', this, o)) {
			// set loading indicator
			childNode.getUI().beforeLoad();
			Ext.Ajax.request(o);
		}
	} 
	
		
	,appendFolderChild:function(childNode) {

		var params = this.applyBaseParams();
		params[this.paramNames.cmd] = this.cmdNames.insertFolder;
		params[this.paramNames.id] = childNode.parentNode.id;
		params[this.paramNames.text] = childNode.text;

		var o = Ext.apply(this.getOptions(), {
			 action:'insertFolder'
			,node:childNode
			,params:params
		});
		

		if(false !== this.fireEvent('beforeinsertfolderrequest', this, o)) {
			// set loading indicator
			childNode.getUI().beforeLoad();
			Ext.Ajax.request(o);
		}
	} 

	
	
	/**
	 * 得到ajax请求
	 * Returns options for server request
	 * @return {Object} options for request
	 * @private
	 */
	,getOptions:function() {
		return {
			 url:this.loader.url || this.loader.dataUrl || this.url || this.dataUrl
			,method:this.loader.method || this.method || 'POST'
			,scope:this
			,callback:this.actionCallback
		};
	} 

	/**
	 * 插入节点事件处理函数
	 * appendChild action handler
	 * @param {Boolean} insert Do not append but insert flag
	 * @private
	 */
	,onAppendChild:function(insert) {
		this.actionNode = this.actionNode || this.selectedNode;
		if(!this.actionNode) {
			return;
		}
		var node = this.actionNode;
		if (!this.enableC2P) {
			node = this.actionNode.isLeaf() ? this.actionNode.parentNode : this.actionNode;
		}
		var child;
		node.expand(false, false, function(n) {
			if(true === insert) {
				// loaded True表示当前资源已加载到浏览器渲染。此项是为了不会重复下载资源时的判读根据
				child = n.insertBefore(this.loader.createNode({text:this.newText, loaded:true}), n.firstChild);
			}
			else {
				child = n.appendChild(this.loader.createNode({text:this.newText, loaded:true}));
			}
		}.createDelegate(this));

		this.editor.creatingNode = true;
		if(true === insert) {
			this.editor.on({
				complete:{
					scope:this,
					single:true,
					fn:this.onInsertEditComplete
				}
			});
		}
		else {
			this.editor.on({complete:{scope:this, single:true, fn:this.onAppendEditCompete}});
		}

		this.editor.triggerEdit(child);
		this.actionNode = null;

	} 
	
	
	/**
	 * 新建文件夹
	 */
	,onInsertFolder:function(){
		this.actionNode = this.actionNode || this.selectedNode;
		if(!this.actionNode) {
			return;
		}
		var node = this.actionNode.isLeaf() ? this.actionNode.parentNode : this.actionNode;
		var child;
		node.expand(false, false, function(n) {
			child = n.appendChild(this.loader.createNode({leaf:false,text:this.insertFolderText, loaded:false}));
		}.createDelegate(this));

		this.editor.creatingNode = true;
		this.editor.on({
			complete  : {
				scope    : this,
				single   : true, 
				fn       : this.onAppendFolderEditCompete
			}
		});

		this.editor.triggerEdit(child);
		this.actionNode = null;
	},
	
	
	
	
	
	
	
	onAppendFolderEditCompete:function(editor, newText, oldText) {
		this.appendFolderChild(editor.editNode);
	}, 
	
	/**
	 * Editing complete event handler
	 *
	 * @param {Ext.tree.TreeEditor} editor
	 * @param {String} newText 
	 * @param {String} oldText
	 * @private
	 */
	onAppendEditCompete:function(editor, newText, oldText) {
		this.appendChild(editor.editNode);
	}, 
	
	

	
	
	/**
	 * Before node drop event handler. Cancels node drop at client but initiates
	 * request to server. Drop is completed if the server returns success
	 *
	 * @param {Object} e DD object
	 * @private
	 */
	onBeforeNodeDrop:function(e) {
		this.moveNode(e);
		e.dropStatus = true;
		return false;

	}, 

	
	/**
	 * 菜单事件处理函数
	 * contextmenu event handler. Shows context menu
	 *
	 * @param {Ext.tree.TreeNode} node right-clicked node
	 * @param {Ext.EventObject} e event
	 */
	onContextMenu:function(node, e) {
			if(node!=this.getRootNode()){
		var menu = this.contextMenu;
		if (node.id != undefined) {
		    node.select();
		    menu.showAt(e.getXY());
		}
			}

		
		/*
		//alert("time--->"+0);
		//alert("node.id--->"+node.id);
		// no node under click - use root node
		if(node.browserEvent) {
			//alert("time--->"+1);
			this.getSelectionModel().clearSelections();
			menu.showAt(node.getXY());
			this.actionNode = this.getRootNode();
			node.stopEvent();
		}
		// a node under click
		else {
			//alert("time--->"+1);
			node.select();
			this.actionNode = node;
			var alignEl = node.getUI().getEl();
			var xy = menu.getEl().getAlignToXY(alignEl, 'tl-tl', [0, 18]);
			//alert(e.getXY()[0]+"  ||  "+ xy[1]);
			menu.showAt([e.getXY()[0], xy[1]]);
			e.stopEvent();
		}

		var actions = this.actions;
		var disable = true !== this.editable || !this.actionNode;
		actions.appendChild.setDisabled(disable);
		actions.renameNode.setDisabled(disable);
		actions.removeNode.setDisabled(disable);
		actions.insertChild.setDisabled(disable);	*/
	}, 


	/**
	 * Event handler of editor complete event
	 * Calls rename node but returns false as ui is updated later on success
	 *
	 * @param {Ext.tree.TreeEditor} editor
	 * @param {String} newText
	 * @param {String} oldText
	 * @return {Boolean} false - to cancel immediate editing/renaming
	 */
	onEditComplete:function(editor, newText, oldText) {
		if(editor.creatingNode) {
			editor.creatingNode = false;
			return;
		}

		this.renameNode(editor.editNode, newText);
		return false;
	} 


	/**
	 * 展开所有
	 * expandAll action handler
	 *
	 * @private
	 */
	,onExpandAll:function() {
		this.getRootNode().expand(true, true);
	} 


	/**
	 *  展开
	 * expandNode action handler
	 *
	 * @private
	 */
	,onExpandNode:function() {
		(this.actionNode || this.selectedNode || this.getRootNode()).expand(true, true);
	} 

	/** 
	 * 折叠所有
	 * collapseAll action handler
	 *
	 * @private
	 */
	,onCollapseAll:function() {
		this.getRootNode().collapse(true, true);
	} 

	
	/**
	 * 折叠
	 * collapseNode action handler
	 *
	 * @private
	 */
	,onCollapseNode:function() {
		(this.actionNode || this.selectedNode || this.getRootNode()).collapse(true, true);
	} 

	/**
	 * 新建文件完成 事件处理函数
	 * insertNode editing completed event handler
	 *
	 * @param {Ext.tree.TreeEditor} editor
	 * @param {String} newText
	 * @param {String} oldText
	 * @private
	 */
	,onInsertEditComplete:function(editor, newText, oldText) {
		this.appendChild(editor.editNode, true);
	} 
	
	
	/**
	 * 新建文件 事件处理函数
	 * insertChild action handler
	 *
	 * @private
	 */
	,onInsertChild:function() {
		this.onAppendChild(true);
	} 

	/**
	 * 按DELETE 删除
	 * Delete key event handler. Calls delete action if a node is selected
	 *
	 * @param {Number} key
	 * @param {Ext.EventObject} e 
	 */
	,onKeyDelete:function(key, e) {
		this.actionNode = this.getSelectionModel().getSelectedNode();
		this.actions.removeNode.execute();
	} 


	/**
	 * 按F2重命名
	 * Edit key (F2) event handler. Triggers editing.
	 *
	 * @param {Number} key
	 * @param {Ext.EventObject} e 
	 */
	,onKeyEdit:function(key, e) {
		var node = this.getSelectionModel().getSelectedNode();
		if(node && true === this.editable) {
			this.actionNode = node;
			this.onRenameNode();
		}
	} 

	
	/**
	 * 拖拽OVER 处理函数
	 * nodedragover event handler. Resets leaf flag if appendig to leafs is allowed
	 *
	 * @param {Object} e DD object
	 * @private
	 */
	,onNodeDragOver:function(e) {
		if(true === this.allowLeafAppend) {
			e.target.leaf = false;
		}
	} 

	
	/**
	 * nodedrop event handler
	 *
	 * @param {Object} e DD object
	 * @private
	 */
	,onNodeDrop:function(e) {
	} 

	
	/**
	 * onRender override
	 *
	 * @private
	 */
	,onRender:function() {
		Ext.ux.tree.RemoteTreePanel.superclass.onRender.apply(this, arguments);
		if(false === this.rootVisible && this.contextMenu) {
			this.el.on({contextmenu:{scope:this, fn:this.onContextMenu, stopEvent:true}});
		}
	} 


	
	/**
	 * 移动Node 事件处理函数
	 * removeNode action handler
	 *
	 * @private
	 */
	,onRemoveNode:function() {
		this.actionNode = this.actionNode || this.selectedNode;
		if(!this.actionNode) {
			return;
		}
		var node = this.actionNode;
		this.removeNode(node);
		this.actionNode = null;
	} 

	
	
	/**
	 * 重命名 事件处理函数
	 * renameNode action handler
	 *
	 * @private
	 */
	,onRenameNode:function() {
		this.actionNode = this.actionNode || this.selectedNode;
		if(!this.actionNode) {
			return;
		}
		var node = this.actionNode;
		this.editor.triggerEdit(node, 10);
		this.actionNode = null;
	} 

	
	
	/**
	 * Adds a custom class to drag ghost - default icons are always used otherwise
	 *
	 * @private
	 */
	,onStartDrag:function() {
		this.dragZone.proxy.ghost.addClass(this.cls || this.initialConfig.cls || '');
	} 

	
	
	
	/**
	 * 向server请求 移动节点
	 * Requests server to move node. Node move has been initiated at client but
	 * has been cancelled. The move is completed if the server returns succes.
	 *
	 * @param {Object} e DD object
	 * @private
	 */
	,moveNode:function(e) {
		// 向后台传递参数
		var params = this.applyBaseParams();
		params[this.paramNames.cmd] = this.cmdNames.moveNode;
		params[this.paramNames.id] = e.dropNode.id;
		params[this.paramNames.target] = e.target.id;
		params[this.paramNames.point] = e.point;

		var o = Ext.apply(this.getOptions(), {
			 action:'moveNode'
			,e:e
			,node:e.dropNode
			,params:params
		});

		if(false !== this.fireEvent('beforemoverequest', this, o)) {
			// set loading indicator
			e.dropNode.getUI().beforeLoad();
			Ext.Ajax.request(o);
		}
	} 

	
	/**
	 * 发送请求到Server删除节点，如果Server返回success 
	 * Sends request to server to remove the node. Node is removed from UI
	 * if the server returns success.
	 *
	 * @param {Ext.tree.TreeNode} node to remove
	 * @private
	 */
	,removeNode:function(node) {
		// node.getDepth() 返回该节点的深度（根节点的深度是0)
		if(0 === node.getDepth()) {
			return;
		}
		Ext.Msg.show({
			 title:this.deleteText
			,msg:this.reallyWantText + ' ' + this.deleteText.toLowerCase() + ': <b>' + node.text + '</b>?'
			,icon:Ext.Msg.QUESTION
			,buttons:Ext.Msg.YESNO
			,scope:this
			,fn:function(response) {
				if('yes' !== response) {
					return;
				}

				var params = this.applyBaseParams();
				params[this.paramNames.cmd] = this.cmdNames.removeNode;
				params[this.paramNames.id] = node.id;

				var o = Ext.apply(this.getOptions(), {
					 action:'removeNode'
					,node:node
					,params:params
				});

				if(false !== this.fireEvent('beforeremoverequest', this, o)) {
					// set loading indicator
					node.getUI().beforeLoad();
					Ext.Ajax.request(o);
				}
			}
		});
	} 

	
	/**
	 * 发送请求到服务器修改文件夹（重命名）
	 *
	 * @param {Ext.tree.TreeNode} node Node to rename
	 * @param {String} newText New name for the node
	 * @private
	 */
	,renameNode:function(node, newText) {

		var params = this.applyBaseParams();
		params[this.paramNames.cmd] = this.cmdNames.renameNode;
		params[this.paramNames.id] = node.id;
		params[this.paramNames.newText] = newText;
		params[this.paramNames.oldText] = node.text || '';

		var o = Ext.apply(this.getOptions(), {
			 action:'renameNode'
			,node:node
			,params:params
		});

		if(false !== this.fireEvent('beforerenamerequest', this, o)) {
			// set loading indicator
			node.getUI().beforeLoad();
			Ext.Ajax.request(o);
		}
	}
	
	
	/**
	 * 显示错误信息
	 *
	 * @param {String} msg Error message to display
	 * @param {String} title Title of the error dialog. Defaults to 'Error'
	 */
	,showError:function(msg, title) {
		Ext.Msg.show({
			 title:title || this.errorText
			,msg:msg
			,icon:Ext.Msg.ERROR
			,buttons:Ext.Msg.OK
		});
	} 
	
		

}); 
 
Ext.reg('remotetreepanel', Ext.ux.tree.RemoteTreePanel); 
 
